package cn.jtfadmin.core.config.shiro;

import cn.jtfadmin.base.data.jpa.utils.TxUtils;
import cn.jtfadmin.base.lang.common.security.UserDetails;
import cn.jtfadmin.base.lang.common.service.BaseService;
import cn.jtfadmin.base.lang.common.utils.AkUtils;
import cn.jtfadmin.base.lang.config.ApplicationHolder;
import cn.jtfadmin.base.shiro.config.UserBuilder;
import cn.jtfadmin.base.shiro.events.UserBuildSuccessEvent;
import cn.jtfadmin.core.modules.sys.domain.dto.SysUserModelDTO;
import cn.jtfadmin.core.modules.sys.domain.dto.UserMenuRDTO;
import cn.jtfadmin.core.modules.sys.domain.entity.SysUserEntity;
import cn.jtfadmin.core.modules.sys.service.SysUserPermissionActionService;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.springframework.core.ResolvableType;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

@Component
public class SysUserBuilder implements UserBuilder {
    @Override
    public Optional<UserDetails> build(AuthenticationToken token) {
        if(token instanceof UsernamePasswordToken){
            UsernamePasswordToken t = UsernamePasswordToken.class.cast(token);
            String username = t.getUsername();
            return TxUtils.execute(()->{
                BaseService<SysUserEntity> bean = (BaseService<SysUserEntity>) ApplicationHolder.getApplicationContext().getBeanProvider(ResolvableType.forClassWithGenerics(BaseService.class, SysUserEntity.class)).getIfUnique();
                Optional<SysUserEntity> optional = bean.findOneByField("username",username);
                if(optional.isPresent()){
                    return Optional.ofNullable(build(optional.get()));
                }
                return Optional.empty();

            });
        }
        return Optional.empty();
    }

    @Override
    public Optional<UserDetails> build(String userId, String userType) {
        if(Objects.equals(userType, UserDetailsPropertiesKey.TYPE)){
            return TxUtils.execute(()->{
                BaseService<SysUserEntity> bean = (BaseService<SysUserEntity>) ApplicationHolder.getApplicationContext().getBeanProvider(ResolvableType.forClassWithGenerics(BaseService.class, SysUserEntity.class)).getIfUnique();
                Optional<SysUserEntity> optional = bean.findById(userId);
                if(optional.isPresent()){
                    return Optional.ofNullable(build(optional.get()));
                }
                return Optional.empty();
            });
        }
        return Optional.empty();
    }



    private UserDetails build(SysUserEntity sysUserEntity){
        UserDetails userDetails = new UserDetails();
        userDetails.setUserId(sysUserEntity.getId());
        userDetails.setDisplayName(sysUserEntity.getRealname());
        userDetails.setPassword(sysUserEntity.getPassword());
        userDetails.setType(UserDetailsPropertiesKey.TYPE);
        userDetails.setHeadImg(sysUserEntity.getHeadimg());

        Map<String, Object> propertie = userDetails.getProperties();
        UserMenuRDTO userMenuRDTO = ApplicationHolder.getApplicationContext()
                .getBean(SysUserPermissionActionService.class).findUserMenu(sysUserEntity);
        propertie.put(UserDetailsPropertiesKey.MENU_PERMISSION_TYPE, userMenuRDTO);

        SysUserModelDTO userModelDTO = new SysUserModelDTO();
        AkUtils.copyProperties(sysUserEntity, userModelDTO);
        propertie.put(UserDetailsPropertiesKey.USER_MODEL_TYPE, userModelDTO);

        Set<String> managerDepIds = ApplicationHolder.getApplicationContext()
                .getBean(SysUserPermissionActionService.class).findManagerDepIds(sysUserEntity);
        propertie.put(UserDetailsPropertiesKey.USER_MANAGER_DEP_IDS_TYPE, managerDepIds);

        userDetails.setCreateDateTime(LocalDateTime.now());
        Set<String> permissionDataRule = ApplicationHolder.getApplicationContext()
                .getBean(SysUserPermissionActionService.class).findPermissionDataRule(sysUserEntity);
        userDetails.setPermissions(userMenuRDTO.getAuth().stream().map(t->t.getAction()).collect(Collectors.toSet()));
        propertie.put(UserDetailsPropertiesKey.USER_PERMISSION_DATA_RULE_TYPE, permissionDataRule);
        return userDetails;
    }



    @Override
    public void onApplicationEvent(UserBuildSuccessEvent event) {

    }
}
